package com.alstudio.event;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;

final class HandlerPoster extends Handler {

	private final PendingALEventQueue queue;
	private final int maxMillisInsideHandleMessage;
	private final ALEventDeliver eventDeliver;
	private boolean handlerActive;

	HandlerPoster(ALEventDeliver eventDeliver, Looper looper,
			int maxMillisInsideHandleMessage) {
		super(looper);
		this.eventDeliver = eventDeliver;
		this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
		queue = new PendingALEventQueue();
	}

	void enqueue(SubscriptionObject subscriptionObject, Object event) {
		PendingALEvent pendingALEvent = PendingALEvent.obtainPendingPost(
				subscriptionObject, event);
		synchronized (this) {
			queue.enqueue(pendingALEvent);
			if (!handlerActive) {
				handlerActive = true;
				if (!sendMessage(obtainMessage())) {
					throw new Error(
							"Could not send handler message");
				}
			}
		}
	}

	@Override
	public void handleMessage(Message msg) {
		boolean rescheduled = false;
		try {
			long started = SystemClock.uptimeMillis();
			while (true) {
				PendingALEvent pendingALEvent = queue.poll();
				if (pendingALEvent == null) {
					synchronized (this) {
						// Check again, this time in synchronized
						pendingALEvent = queue.poll();
						if (pendingALEvent == null) {
							handlerActive = false;
							return;
						}
					}
				}
				eventDeliver.invokeSubscriber(pendingALEvent);
				long timeInMethod = SystemClock.uptimeMillis() - started;
				if (timeInMethod >= maxMillisInsideHandleMessage) {
					if (!sendMessage(obtainMessage())) {
						throw new Error(
								"Could not send handler message");
					}
					rescheduled = true;
					return;
				}
			}
		} finally {
			handlerActive = rescheduled;
		}
	}
}